/*
 * The MIT License (MIT)
 * Copyright © 2022 Walkline Wang (https://walkline.wang)
 * Gitee: https://gitee.com/walkline/ramcu-mechanical-keypad
 */
#include "app_common.h"
#include "ch9329.h"
#include "key_matrix/key_matrix.h"
#include "uart_common/uart_common.h"

/**
 * 全局变量
 **/
ch9329_chip_info_t g_chip_info;

/**
 * 私有变量
 **/
static uint8_t head[] = {0x57, 0xab};

/* 键盘指示灯状态 */
static volatile uint8_t num_lock_status		= 0;
static volatile uint8_t caps_lock_status	= 0;
static volatile uint8_t scroll_lock_status	= 0;

/**
 * 私有函数
 **/
static uint8_t calculate_checksum(const uint8_t *data, uint8_t len);

/* 检测并记录键盘指示灯状态 */
void ch9329_check_status()
{
	if (g_uart_usb_hid_recv_flag) {
		g_uart_usb_hid_recv_flag = false;

		if (g_usb_hid_buffer[0] == 0x57 && g_usb_hid_buffer[1] == 0xab &&
			g_usb_hid_buffer[2] == 0x00 && g_usb_hid_buffer[3] == 0x81) {
			strcpy(g_chip_info.version, (char*)"v1.x");
			g_chip_info.version[3] = (char)(g_usb_hid_buffer[5] - 0x30 + '0');
			g_chip_info.usb_status = g_usb_hid_buffer[6];
			g_chip_info.num_lock_status = GET_BIT(g_usb_hid_buffer[7], 0);
			g_chip_info.caps_lock_status = GET_BIT(g_usb_hid_buffer[7], 1);
			g_chip_info.scroll_lock_status = GET_BIT(g_usb_hid_buffer[7], 2);

			if (num_lock_status != g_chip_info.num_lock_status) {
				num_lock_status = g_chip_info.num_lock_status;
				num_lock_status ? set_io_low(io_num_lock) : set_io_high(io_num_lock);
#if DEBUG
				printf("num_lock: %s\r\n", num_lock_status ? "on" : "off");
#endif
			}

			if (caps_lock_status != g_chip_info.caps_lock_status) {
				caps_lock_status = g_chip_info.caps_lock_status;
#if DEBUG
				printf("caps_lock: %s\r\n", caps_lock_status ? "on" : "off");
#endif
			}

			if (scroll_lock_status != g_chip_info.scroll_lock_status) {
				scroll_lock_status = g_chip_info.scroll_lock_status;
#if DEBUG
				printf("scroll_lock: %s\r\n", scroll_lock_status ? "on" : "off");
#endif
			}
		}
	}
}

fsp_err_t ch9329_get_info()
{
	uint8_t data_length = 0;
	uint8_t command_length = PACKAGE_LENGTH + data_length;
	uint8_t data[command_length];

	data[0] = head[0];
	data[1] = head[1];
	data[2] = ADDR;
	data[3] = CMD_GET_INFO;
	data[4] = data_length;
	data[5] = 0x03;

	uart_usb_hid_send(data, command_length);

	while (!g_uart_usb_hid_recv_flag) {}
	g_uart_usb_hid_recv_flag = false;

	if ((CMD_GET_INFO | RETURN_MASK) == g_usb_hid_buffer[3]) {
		strcpy(g_chip_info.version, (char*)"v1.x");
		g_chip_info.version[3] = (char)(g_usb_hid_buffer[5] - 0x30 + '0');
		g_chip_info.usb_status = g_usb_hid_buffer[6];
		g_chip_info.num_lock_status = GET_BIT(g_usb_hid_buffer[7], 0);
		g_chip_info.caps_lock_status = GET_BIT(g_usb_hid_buffer[7], 1);
		g_chip_info.scroll_lock_status = GET_BIT(g_usb_hid_buffer[7], 2);

		g_chip_info.num_lock_status ? set_io_low(io_num_lock) : set_io_high(io_num_lock);
		return FSP_SUCCESS;
	}

	return FSP_ERR_ABORTED;
}

void ch9329_reset()
{
	uint8_t data_length = 0;
	uint8_t command_length = PACKAGE_LENGTH + data_length;
	uint8_t data[command_length];

	data[0] = head[0];
	data[1] = head[1];
	data[2] = ADDR;
	data[3] = CMD_RESET;
	data[4] = data_length;
	data[5] = calculate_checksum(data, command_length - 1);

	uart_usb_hid_send(data, command_length);

	while (!g_uart_usb_hid_recv_flag) {}
	g_uart_usb_hid_recv_flag = false;

	if ((CMD_RESET | RETURN_MASK) == g_usb_hid_buffer[3]) {
		printf("chip_reset status: %d\r\n", g_usb_hid_buffer[5]);
	}
}

void ch9329_send_kb_data()
{
	uint8_t data_length = 8;
	uint8_t command_length = PACKAGE_LENGTH + data_length;
	uint8_t data[command_length];

	data[0] = head[0];
	data[1] = head[1];
	data[2] = ADDR;
	data[3] = CMD_SEND_KB_GENERAL_DATA;
	data[4] = data_length;
	data[5] = 0x00;
	data[6] = 0x00;

	for (int i=0; i<6; i++) {
		data[i + 7] = g_normal_keycode_list[i];
	}

	data[13] = calculate_checksum(data, command_length - 1);

	uart_usb_hid_send(data, command_length);

	while (!g_uart_usb_hid_recv_flag) {}
	g_uart_usb_hid_recv_flag = false;

	if ((CMD_SEND_KB_GENERAL_DATA | RETURN_MASK) == g_usb_hid_buffer[3]) {
#if DEBUG
		printf(", send_kb_data status: %d\r\n", g_usb_hid_buffer[5]);
#endif
	}
}

static uint8_t calculate_checksum(const uint8_t *data, uint8_t len)
{
	uint16_t sum_value = 0;

	for (int i=0; i<len; i++) {
		sum_value += data[i];
	}

	return (uint8_t) (sum_value & 0xff);
}
